package com.example.qxfw.dysjrh.utils;
import com.dmgis.entity.DmGridInfo;
import com.dmgis.util.DateTime;
import com.dmgis.weblib.GridAnalysis;
import com.example.qxfw.common.util.ByteToFileUtil;
import com.example.qxfw.dysjrh.entity.ContourSetting;
import com.example.qxfw.dysjrh.entity.GridDataPicAndXY;
import com.example.qxfw.dysjrh.entity.QxGridFile;
import com.example.qxfw.dysjrh.entity.vo.GridVo;
import com.example.qxfw.dysjrh.entity.vo.My3DPointVo;
import com.example.qxfw.dysjrh.entity.vo.WindPointVo;
import com.example.qxfw.dysjrh.service.impl.GridServiceImpl;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author wzt
 * @date 2025/01/03
 */
@Service
@RequiredArgsConstructor
public class GridUtil {
    //前端能接收的最大行列数
    private final int DEFAULT_MAX_COLUMNS_ROWS = 60;
    private static final Logger logger = LoggerFactory.getLogger(GridServiceImpl.class);
    private static final int MAX_FILES = 1000;


    @Autowired
    private ByteToFileUtil byteToFileUtil;

    public ArrayList<My3DPointVo> ReadGridFile(String[] gridFiles) {
        if (gridFiles.length == 0){
//            // 处理空文件数组的情况，例如抛出异常或返回默认值
//            throw new IllegalArgumentException("gridFiles is null or empty");
            logger.warn("gridFiles is null or empty");
            return new ArrayList<>();
        }
        ArrayList<My3DPointVo> pList = new ArrayList<>();
        GridAnalysis gridAnalysis = new GridAnalysis();
        GridAnalysis analysis = new GridAnalysis();
        //稀释间隔
        int interval = 1;
        try {
            for (int i = 0; i < gridFiles.length; i++) {
                File gridFile = new File(gridFiles[i]);
                if (gridFile.exists()) {
                    analysis.openFile(gridFile.getPath());
                    gridAnalysis = addGrid(analysis, gridAnalysis, 0.5f, 0.5f);
                }
                else {
                    logger.warn("File does not exist: {}", gridFiles[i]);
                }
            }
            DmGridInfo gridInfo = gridAnalysis.getGridInfo();
            if (gridInfo == null){
//                // 处理 gridInfo 为 null 的情况，例如抛出异常或返回默认值
//                throw new IllegalStateException("gridInfo is null");
                logger.warn("gridInfo is null, returning an empty list");
                return new ArrayList<>();
            }
            double xmin = gridInfo.getxMin();
            double ymin = gridInfo.getyMin();
            double xmax = gridInfo.getxMax();
            double ymax = gridInfo.getyMax();
            int row = gridInfo.getRows();
            int col = gridInfo.getCols();
            double rowSpan = (ymax - ymin) / (row - 1);
            double colSpan = (xmax - xmin) / (col - 1);

            //网格数据稀释，格点数据行列数不能超过限定值
            if (row > DEFAULT_MAX_COLUMNS_ROWS || col > DEFAULT_MAX_COLUMNS_ROWS) {
                //用行列数中的较大者获取稀释间隔
                int max = row > col ? row : col;
                interval = (int) Math.ceil((double)max / DEFAULT_MAX_COLUMNS_ROWS);
            }
            for (int i = 0; i < row; i += interval)
                for (int j = 0; j < col; j += interval) {
                    double x = xmin + j * colSpan;
                    double y = ymin + i * rowSpan;
                    //数值保留一位小数
                    double z =  Math.round(gridAnalysis.getValue(i, j) * 10) / 10.0;
                    My3DPointVo point = new My3DPointVo(x, y, z);
                    pList.add(point);
                }
                //加上最后一行和最后一列的数据
                if ((row - 1) % interval != 0) {
                    for (int i = 0; i < col; i += interval) {
                        double x = xmin + i * colSpan;
                        double y = ymin + (row - 1) * rowSpan;
                        double z = Math.round(gridAnalysis.getValue(row - 1, i) * 10) / 10.0;
                        My3DPointVo point = new My3DPointVo(x, y, z);
                        pList.add(point);
                    }
                }
                if ((col - 1)  % interval != 0) {
                    for (int j = 0; j < row - 1; j += interval) {
                        double x = xmin + (col - 1) * colSpan;
                        double y = ymin + j * rowSpan;
                        double z = Math.round(gridAnalysis.getValue(j, col - 1) * 10) / 10.0;
                        My3DPointVo point = new My3DPointVo(x, y, z);
                        pList.add(point);
                    }
                    //当行列数都取不到最后一行时需要加上最后一个点
                    if((row - 1) % interval != 0)
                    {
                        double x = xmin + (col - 1) * colSpan;
                        double y = ymin + (row - 1) * rowSpan;
                        double z = Math.round(gridAnalysis.getValue(row - 1, col - 1) * 10) / 10.0;
                        My3DPointVo point = new My3DPointVo(x, y, z);
                        pList.add(point);
                    }
                }
        }
        catch (Exception ex) {
//            ex.printStackTrace();
            logger.error("Error reading grid files", ex);
        }
        return pList;
    }

    /**
     * 读取风格点文件
     * @param windFile 风格点文件
     * @return
     */
    public ArrayList<WindPointVo> ReadWinGridFiles(String[] windFile) {
        if(windFile.length % 2 != 0){
            logger.error("风格点文件个数必须为偶数");
            throw new IllegalArgumentException("风格点文件个数必须为偶数");
        }
        ArrayList<WindPointVo> pList = new ArrayList<>();
        GridAnalysis GridAnalysisU = new GridAnalysis();
        GridAnalysis GridAnalysisV = new GridAnalysis();
        //获取格点数据
        GridAnalysis analysisU = new GridAnalysis();
        GridAnalysis analysisV = new GridAnalysis();
        //稀释间隔
        int interval = 1;
        try {
            //计算加权平均的风速和风向
            for (int m = 0; m < windFile.length; m += 2) {
                //依次第一个为u风格点文件,第二个为v风格点文件
                File uFile = new File(windFile[m]);
                File vFile = new File(windFile[m + 1]);
                 if(!uFile.exists() || !vFile.exists()){
                     continue;
                 }

                analysisU.openFile(windFile[m]);
                analysisV.openFile(windFile[m + 1]);
                DmGridInfo dmGridDataInfo = analysisU.getGridInfo();
                double xmin = dmGridDataInfo.getxMin();
                double ymin = dmGridDataInfo.getyMin();
                double xmax = dmGridDataInfo.getxMax();
                double ymax = dmGridDataInfo.getyMax();
                int row = dmGridDataInfo.getRows();
                int col = dmGridDataInfo.getCols();
                if(row == 0 || col == 0){
                    continue;
                }
                for (int i = 0; i < row; i++)
                    for (int j = 0; j < col; j++) {
                        //根据U,V值求风速风向
                        double[] wind = UVConvertToWind(analysisU.getValue(i, j), analysisV.getValue(i, j));
//                        analysisU.setValue(i, j, (float)wind[0]);
//                        analysisV.setValue(i, j, (float)wind[1]);
                        analysisU.setValue(i, j, (float)((Math.round(wind[1]) *10)  / 10.0));
                        analysisV.setValue(i, j, (float)((Math.round(wind[0]) *10)  / 10.0));
                    }
                    //加权平均
                    GridAnalysisU = addGrid(analysisU,GridAnalysisU,0.5f,0.5f);
                    GridAnalysisV = addGrid(analysisV,GridAnalysisV,0.5f,0.5f);
                }

            DmGridInfo gridDataInfo = GridAnalysisU.getGridInfo();
            double xmin = gridDataInfo.getxMin();
            double ymin = gridDataInfo.getyMin();
            double xmax = gridDataInfo.getxMax();
            double ymax = gridDataInfo.getyMax();
            int row = gridDataInfo.getRows();
            int col = gridDataInfo.getCols();
            if(row == 0 || col == 0){
                return pList;
            }
            double rowSpan = (ymax - ymin) / (row + 1);
            double colSpan = (xmax - xmin) / (col + 1);
            //网格数据稀释，格点数据行列数不能超过限定值
            if(row > DEFAULT_MAX_COLUMNS_ROWS || col > DEFAULT_MAX_COLUMNS_ROWS){
                //用行列数中的较大者获取稀释间隔
                double max = row > col ? row : col;
                interval = (int)Math.ceil((double)max/DEFAULT_MAX_COLUMNS_ROWS);
            }
            for (int i = 0; i < row; i+=interval)
                for (int j = 0; j < col; j+=interval) {
                    double x = xmin + j * colSpan;
                    double y = ymin + i * rowSpan;
                    double windU = GridAnalysisU.getValue(i, j);
                    double windV = GridAnalysisV.getValue(i, j);
                    WindPointVo point = new WindPointVo(x, y, windU, windV);
                    pList.add(point);
                }
            //加上最后一行和最后一列的数据
            if (row % interval != 0) {
                for (int i = 0; i < col; i += interval) {
                    double x = xmin + i * colSpan;
                    double y = ymin + (row - 1) * rowSpan;
                    double windU = GridAnalysisU.getValue(row - 1, i);
                    double windV = GridAnalysisV.getValue(row - 1, i);
                    WindPointVo point = new WindPointVo(x, y, windU, windV);
                    pList.add(point);
                }
            }
            if (col % interval != 0) {
                for (int j = 0; j < row - 1; j += interval) {
                    double x = xmin + (col - 1) * colSpan;
                    double y = ymin + j * rowSpan;
                    double windU = GridAnalysisU.getValue(j, col - 1);
                    double windV = GridAnalysisV.getValue(j, col - 1);
                    WindPointVo point = new WindPointVo(x, y, windU, windV);
                    pList.add(point);
                }
                //当行列数都取不到最后一行时需要加上最后一个点
                if(row % interval != 0 )
                {
                    double x = xmin + (col - 1) * colSpan;
                    double y = ymin + (row - 1) * rowSpan;
                    double windU = GridAnalysisU.getValue(row - 1, col - 1);
                    double windV = GridAnalysisV.getValue(row - 1, col - 1);
                    WindPointVo point = new WindPointVo(x, y, windU, windV);
                    pList.add(point);
                }
            }
            } catch(Exception e){
                logger.error("Failed to read windPoint files",e);
                throw new IllegalStateException("Failed to read windPoint files");
            }
            return pList;
    }

    public double[] UVConvertToWind(double u, double v) {
        double[] wind = new double[2];
        try {
            double windAngle = 0;
            double p = 180 / Math.PI;
            double k = Math.PI / 2; //90°对应的π值
            double windValue = Math.sqrt(u * u + v * v);
            if (v != 0) {
                if (u == 0)
                    windAngle = v > 0 ? 0 : 2 * k;
                if (u > 0)
                    windAngle = v > 0 ? (k - Math.atan(v / u)) : (k + Math.atan(-v / u));
                if (u < 0)
                    windAngle = v > 0 ? (3 * k + Math.atan(-v / u)) : (3 * k - Math.atan(v / u));
            } else {
                if (u > 0)
                    windAngle = k;
                if (u < 0)
                    windAngle = 3 * k;
                if (u == 0)
                    windAngle = 0;
            }

            windAngle = windAngle * p;
            if (windAngle > 180)
                windAngle = windAngle - 180;
            else
                windAngle = windAngle + 180;
            wind[0] = Double.parseDouble(String.format("%.1f",windValue));
            wind[1] = Double.parseDouble(String.format("%.0f",windAngle));
        } catch (Exception ex) {
            System.out.println("风UV转换失败：" + ex.getStackTrace());
        }
        return wind;
    }

    /**
     * 将格点数据存到本地文件中
     * @param tempFilePath 文件地址
     * @param gridVo  格点数据
     * @return  格点文件路径
     * @throws ParseException
     */
    public String getGridData(String tempFilePath, GridVo gridVo) throws ParseException {
        if(tempFilePath == null || tempFilePath.isEmpty() || gridVo == null){
            logger.error("tempFilePath or gridVo is null");
            throw new IllegalArgumentException("tempFilePath or gridVo is null");
        }

        FileUtil fileUtil = new FileUtil();
        try{
            DateTime forecastTime = DateTime.parseDateTime(gridVo.getDatechar()).AddHours(Integer.parseInt(gridVo.getTimechar()));
            String ntimes = String.format("%03d", Integer.parseInt(gridVo.getNtimes()));
            String gridType = gridVo.getType();
            String fileName = gridType + "." + forecastTime.toDateTimeString("yyyyMMddHH.")
                    + ntimes;
            //判断文件是否存在
            Path filePath = Paths.get(tempFilePath, fileName);
            fileUtil.mkDirs(tempFilePath);// 创建文件夹
            // 当格点文件数量达到1000时清除
            fileUtil.ClearTempFiles(tempFilePath, MAX_FILES);
            File gridFile = filePath.toFile();
            boolean fileExists = gridFile.exists();

            if (!fileExists) {
                //检查mongodb是否存在该文件
                byte[] data = gridVo.getData();
                //byte[] data = HttpRequest.get(DbConfig.mongoSelectUrl, map, true).bytes();
                if (data != null && data.length > 10) {
                    fileUtil.bytesToFile(data, gridFile.getPath());
                    fileExists = true;
                }
            }
            return fileExists ? filePath.toString() : "";
        }catch (Exception e) {
            logger.error("Failed to read grid files",e);
            throw new IllegalStateException("Failed to read grid files");
        }
    }

    /**
     * 两个格点数据求加权平均值,要求行列数相等，不相等默认返回第一个格点数据
     * @param grd1
     * @param grd2
     * @param yz1
     * @param yz2
     * @return
     */
    public GridAnalysis addGrid(GridAnalysis grd1, GridAnalysis grd2,float yz1, float yz2) {
            if(grd1.getInfo() == null || grd2.getInfo() == null) {
                return grd1;
            }
            try
            {

                DmGridInfo info1 = grd1.getGridInfo();
                DmGridInfo info2 = grd2.getGridInfo();
                if (info1.getRows() != info2.getRows() || info1.getCols() != info2.getCols()) {
                    return grd1;
                }
                //创建新的GridAnalysis对象以避免修改原始数据
                GridAnalysis grd = grd1;
                DmGridInfo info = grd.getGridInfo();
                //加权平均值
                for (int i = 0; i < info.getRows(); ++i) {
                    for (int j = 0; j < info.getCols(); ++j) {
                        grd.setValue(i,j, grd1.getValue(i,j) * yz1 + grd2.getValue(i,j) * yz2);
                    }
                }
                return grd;
            }catch (Exception e){
                logger.error("Failed to addGrid",e);
                e.printStackTrace();
                return grd1;
        }
    }


    /**
     * 处理格点数据，生成图片。
     *
     * @param qxGridFile 包含格点数据的 QxGridFile 对象
     * @return 经纬度值列表，包含每个格点的经度、纬度和对应值
     * @throws IOException 如果在处理过程中发生 I/O 异常
     */
    public GridDataPicAndXY processGridDataPicAndXY(QxGridFile qxGridFile, List<ContourSetting> contourSettings,String gridFile1) throws IOException {
        // 获取格点数据的字节数组
        byte[] data = qxGridFile.getData();
        // 生成文件名，以格点文件的 ID 作为基础
        String fileName = qxGridFile.get_id() + ".grid";
        // 将字节数组写入临时格点文件并获取文件路径
        String gridFile = byteToFileUtil.byteArrayToGridFile(data, fileName, gridFile1);
        System.err.println(gridFile);
        File fileCheck = new File(gridFile);
        if (!fileCheck.exists()) {
            return null;
        }
        // 创建 GridAnalysis 对象并打开格点文件
        GridAnalysis grid = new GridAnalysis();
        grid.openFile(gridFile);
        File file = com.example.qxfw.common.util.FileUtil.getFile("png");
        if (contourSettings == null || contourSettings.size() == 0){
            //计算最大最小值，配合自动分级做
//        Arrays.sort(grid.getfValS());
//        gridInfo.setyMin(grid.getfValS()[0]);
//        gridInfo.setxMax(grid.getfValS()[grid.getfValS().length - 1]);
            grid.drawGridInfo(10, file.getAbsolutePath(), null, null,10);//绘制图片
        }

        else {
        ArrayList<Float> colorlist = new ArrayList<Float>();
        ArrayList<String> colors = new ArrayList<String>();
        //按照国标分级
        for (ContourSetting set : contourSettings) {
            colorlist.add(Float.parseFloat(set.getElementvalue().toString()));
            int color = set.getElementcolor();
            int b = color & 0xff;
            int g = (color >> 8) & 0xff;
            int r = (color >> 16) & 0xff;
            String color16 = String.format("#%02X%02X%02X", r, g, b);
            colors.add(color16);
        }
        grid.drawGridInfo(10, file.getAbsolutePath(), colorlist, colors, 15); }//绘制图片
        byte[] filedata = com.example.qxfw.common.util.FileUtil.getBytesByFile(file.getAbsolutePath());

        file.delete();//只保留data，文件直接删除
        GridDataPicAndXY gridDataPicAndXY = new GridDataPicAndXY(filedata, grid.getGridInfo());

        return gridDataPicAndXY;
    }



}

